import matplotlib
import matplotlib.pyplot as plt
import numpy as np
# ---------- 1. 控制点 ----------
P0 = np.array([1.0, 0.0])
P1 = np.array([2.0, -1.0])
P2 = np.array([3.0, -1.0])
P3 = np.array([4.0, 2.0])
control_pts = [P0, P1, P2, P3]
T = 0.6
# ---------- 2. 第一次插值（t=0.5） ----------
def lerp(a, b, t=T):
    return ( (1-t)*a[0] + t*b[0], (1-t)*a[1] + t*b[1] )

# 绘制 Bézier 曲线（蓝色）
# 使用参数 t 从 0 到 1 采样绘制完整曲线
def de_casteljau(t, ctrl_pts):
    """
    de Casteljau 递归实现
    参数
    ----
    t : float  (0 ≤ t ≤ 1)
        曲线参数
    ctrl_pts : ndarray, shape (n+1, 2)
        控制点列表，n 为 Bézier 曲线次数
    返回
    ----
    point : ndarray, shape (2,)
        参数 t 对应的曲线点
    """
    pts = np.array(ctrl_pts, dtype=float)
    n = pts.shape[0] - 1          # 曲线次数
    # 逐层线性插值
    for r in range(1, n + 1):
        pts[:n - r + 1] = (1 - t) * pts[:n - r + 1] + t * pts[1:n - r + 2]
    return pts[0]

def draw_bezier(aux, points):
    ts = np.linspace(0, 1, 200)
    curve = [de_casteljau(t, points) for t in ts]
    curve_x, curve_y = zip(*curve)
    aux.plot(curve_x, curve_y, color='steelblue', linewidth=2, label='Bézier 曲线')


if __name__ == '__main__':
    Q0 = lerp(P0, P1)   # (1, 5.5)
    Q1 = lerp(P1, P2)   # (5, 1)
    Q2 = lerp(P2, P3)   # (9, 5.5)
    first_layer = [Q0, Q1, Q2]

    # ---------- 3. 第二次插值 ----------
    R0 = lerp(Q0, Q1)   # (3, 3.25)
    R1 = lerp(Q1, Q2)   # (7, 3.25)
    second_layer = [R0, R1]

    # ---------- 4. 第三次插值（曲线上点） ----------
    S0 = lerp(R0, R1)    # (5, 3.25)  <-- 曲线在 t=0.5 处的点
    final_point = S0

    # ---------- 5. 绘制 ----------
    matplotlib.rcParams['font.family'] = 'Microsoft YaHei'  # Windows 常用

    fig, ax = plt.subplots(figsize=(8, 6))

    # 绘制控制多边形（灰色）
    ctrl_x, ctrl_y = zip(*control_pts)
    ax.plot(ctrl_x, ctrl_y, 'k--', linewidth=1, label='控制多边形')

    # 绘制第一次插值连线（灰色）
    first_x, first_y = zip(*first_layer)
    ax.plot(first_x, first_y, 'k--', linewidth=1)

    # 绘制第二次插值连线（灰色）
    second_x, second_y = zip(*second_layer)
    ax.plot(second_x, second_y, 'k--', linewidth=1)

    draw_bezier(ax, control_pts)
    # 绘制点
    ax.scatter(*zip(*control_pts), color='red', s=80, zorder=5, label='控制点')
    ax.scatter(*zip(*first_layer), color='green', s=80, zorder=5, label=f'第1层{T}分点')
    ax.scatter(*zip(*second_layer), color='blue', s=80, zorder=5, label=f'第2层{T}分点')
    ax.scatter(*final_point, color='yellow', s=100, edgecolor='black', zorder=6, label=f'第3层{T}分点')

    # 美化坐标轴
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_title(f'de Casteljau 计算过程（t = {T}）')
    ax.set_aspect('equal', adjustable='box')
    ax.grid(True, linestyle='--', alpha=0.5)
    ax.legend(loc='upper left')

    plt.show()
